#include "fiber.h"

bool debug = false;

static std::atomic<uint64_t> s_fiber_id {0};  // 下一个协程id
static std::atomic<uint64_t> s_fiber_count {0}; // 协程计数

// 当前协程
static thread_local Fiber* t_fiber = nullptr;  
// 主协程
static thread_local Fiber::ptr t_threadFiber = nullptr; 
// 调度协程
static thread_local Fiber::ptr t_scheduler_fiber = nullptr;


/**
 * @brief 构造函数
 * @attention 无参构造函数，用于创建第一个协程，即线程主函数对应的协程
 * 该协程只能由GetThis方法进行调用，故为私有
 */
Fiber::Fiber(){
    SetThis(this);
    m_state = RUNNING;

    if(getcontext(&m_ctx)){ // 获取上下文？
        ctd:cerr<<"Fiber() failed"<<endl;
        pthread_exit(NULL);
    }


    ++s_fiber_count;
    m_id = s_fiber_id ++;  // id从0开始
    if(debug) std::cout << "Fiber::Fiber() main id = "<< m_id << std::endl;
}

/**
 * @brief 创建新协程
 */
Fiber::Fiber(std::function<void()> cb, size_t stack_size, bool run_in_scheduler):
m_cb(cb), m_runInScheduler(run_in_scheduler)
{
    m_state= READY;
   

    // 分配协程栈空间
    m_stacksize = stack_size ? stack_size : 128000;
    m_stack = malloc(m_stacksize); // 申请一块空间作为新协程的栈

    if(getcontext(&m_ctx)){
        cout<<"getcontext failed"<<endl;
    }

    m_ctx.uclink = nullptr;
    m_ctx.uc_stack.ss_sp = m_stack;  // 栈指针
    m_ctx.uc_stack.ss_size = m_stack_size;  // 栈大小

    // 创建上下文
    makecontext(&m_ctx, &Fiber::MainFunc, 0);

     ++s_fiber_count;  // 协程计数器计数
     m_id = s_fiber_id++;                                           
    
    cout <<"Fiber::Fiber() id = " << m_id << endl;

}

Fiber:: ~Fiber(){
    s_fiber_count--;
    if(m_stack){
        free(m_stack);
    }

    if(debug) std::cout<< "Fiber(): id = " << m_id << std::endl;
}

void SetThis(Fiber *f){
    t_fiber = f;
}

/**
 *@brief 返回当前线程正在执行的协程
 */
Fiber::ptr GetThis(){
    if(t_fiber){
        return t_fiber->shared_from_this();  // 从当前协程获取共享指针
    }

    // 当前没有线程，说明还未初始化
    // 要进行第一个协程的初始化
    Fiber::ptr main_fiber(new Fiber);

    // 初始化的时候会给t_fiber赋值主协程的指针
    assert(t_fiber == main_fiber.get()); 
    t_thread_fiber = main_fiber;
    t_scheduler_fiber = main_fiber.get(); // 主协程默认为调度协程


    return t_fiber->shared_from_this();
}

void Fiber::SetSchedulerFiber(Fiber* f)
{
	t_scheduler_fiber = f;
}


/**
 * @brief 将当前协程切换到执行的状态
 * 
 */
void Fiber::resume(){
    // 不能为结束态或已经为执行态
    assert(m_state != TERM && m_state != RUNING)

    SetThis(this);  // 切换当前协程程为该协程
    m_state = RUNNING;  // 标记当前协程状态为执行态
    if(swapcontext(&(t_threadFiber->m_ctx), &m_ctx)){
        cout << "swapcontext failed." << endl;
    }

}

/**
 * @brief 当前协程让出执行权
 */

void Fiber::yield(){
    // 协程用完之后主动yield，用于回到主线程，此时状态为结束
    assert(m_state == RUNNING || m_state == TERM);

    SetThis(t_threadFiber.get());
    if(m_state != TERM){
        m_state = READY;
    }

    if(swapcontext(&m_ctx, &(t_threadFiber->m_ctx))){
        cout << "swapcontext failed." << endl;
    }
}

/**
 * @brief 协程入口函数，主协程
 */

void Fiber::MainFunc(){
    // 
    Fiber::ptr cur = GetThis(); 
    assert(cur);
    
    cur->m_cb();  // 执行真正的入口函数
    cur->m_cb = nullptr;
    cur_m_state = TERM;

    auto raw_ptr = cur.get(); 
    cur.reset();
    raw_ptr->yield();

}


/**
 * @brief 重置协程
 */
void Fiber::reset(std::function<void()> cb){
    assert(m_stack);
    assert(m_state == TERM);
    m_cb = cb;  // 回调函数设置为新的的函数
    if(getcontext(&m_ctx)){
        cout << "getcontext failed."<< endl;
    }
    
    m_ctx.uclink = nullptr;
    m_ctx.uc_stack.ss_sp = m_stack;
    m_ctx.uc_stack.ss_size = m_stacksize;

    makecontext(&m_ctx, &Fiber::MainFunc, 0);
    m_state = READY;

}